فعّل التنزيلات المرنة والقابلة للاستئناف في تطبيقات الويب. يغطي هذا الدليل الشامل واجهة Background Fetch API وعمال الخدمة والتنفيذ العملي لنقل الملفات الكبيرة بسلاسة، حتى مع انقطاع الشبكة.
إتقان الجلب في الخلفية للواجهة الأمامية: بناء تنزيلات مرنة وقابلة للاستئناف
في عالمنا المترابط بشكل متزايد، لم يعد الويب مجرد مكان للمستندات الثابتة. بل أصبح منصة للتطبيقات الغنية والتفاعلية التي تقدم كل شيء بدءًا من محتوى الفيديو عالي الدقة إلى برامج الأعمال المعقدة والألعاب الغامرة. هذا التطور يجلب تحديًا كبيرًا يجب على المطورين في جميع أنحاء العالم مواجهته: النقل الموثوق للملفات الكبيرة عبر شبكات غالبًا ما تكون غير موثوقة. سواء كان المستخدم في قطار الأنفاق في سيول، أو طالبًا في منطقة ريفية في أمريكا الجنوبية، أو محترفًا يستخدم اتصال واي فاي متقطع في فندق بدبي، فإن انقطاع الاتصال يمكن أن يعني فشل التنزيل، وإحباط المستخدم، وتجربة معطلة. وهنا تبرز واجهة برمجة تطبيقات الجلب في الخلفية (Background Fetch API) كحل يغير قواعد اللعبة.
الطرق التقليدية مثل `fetch()` أو `XMLHttpRequest` قوية، لكنها مرتبطة بشكل جوهري بدورة حياة صفحة الويب. إذا أغلق المستخدم علامة التبويب أو انتقل إلى صفحة أخرى، يتم إنهاء التنزيل. لا توجد آلية مدمجة لبقائه بعد انتهاء جلسة الصفحة. تغير واجهة برمجة تطبيقات الجلب في الخلفية هذا النموذج بشكل أساسي. فهي تسمح لتطبيق الويب بتفويض مهام التنزيل (والرفع) الكبيرة إلى المتصفح نفسه، الذي يدير بعد ذلك عملية النقل في الخلفية، بشكل مستقل عن أي علامة تبويب واحدة في المتصفح. هذا يعني أن التنزيلات يمكن أن تستمر حتى لو أغلق المستخدم الصفحة، والأهم من ذلك، يمكن إيقافها مؤقتًا واستئنافها تلقائيًا عند تغير اتصال الشبكة. إنها المفتاح لبناء تجارب تنزيل مرنة حقًا وشبيهة بالتطبيقات الأصلية على الويب.
ما هي واجهة برمجة تطبيقات الجلب في الخلفية؟ منظور عالمي
في جوهرها، تعد واجهة برمجة تطبيقات الجلب في الخلفية معيار ويب حديثًا مصممًا لتفويض طلبات الشبكة الكبيرة إلى محرك المتصفح. إنها تمكن المطورين من بدء عمليات تنزيل أو رفع تستمر إلى ما بعد عمر نافذة التطبيق المرئية. هذه ليست مجرد ميزة بسيطة؛ إنها تقنية أساسية لويب أكثر قوة وقدرة.
لننظر في تأثيرها من منظور عالمي. في أجزاء كثيرة من العالم، الإنترنت عالي السرعة والمستقر هو ترف وليس أمرًا مسلمًا به. يمكن أن تكون بيانات الهاتف المحمول باهظة الثمن ومحدودة. لكي يكون التطبيق عالميًا حقًا، يجب أن يراعي هذه الظروف الشبكية المتنوعة. تعد تقنية الجلب في الخلفية تقنية تمكينية للمساواة. فهي تسمح للمستخدم في منطقة ذات اتصال متقطع ببدء تنزيل مقطع فيديو تعليمي أو تحديث برنامج مهم، والثقة في أنه سيكتمل في الخلفية حسبما يسمح به اتصاله، وعدم إهدار البيانات الثمينة على إعادة تنزيل الملفات الفاشلة.
الفوائد الرئيسية للجلب في الخلفية
- المرونة والاستئناف: هذه هي الميزة الرئيسية. يتعامل مدير التنزيل الأساسي في المتصفح مع انقطاعات الشبكة برشاقة. إذا فُقد الاتصال، يتم إيقاف التنزيل مؤقتًا. وعندما يُستعاد الاتصال، يستأنف تلقائيًا من حيث توقف. يحدث هذا دون أي منطق جافاسكريبت معقد للتعامل مع رؤوس `Range` في بروتوكول HTTP.
- الاستمرارية دون اتصال: نظرًا لأن التنزيل يُدار بواسطة عملية المتصفح ويتعامل معه عامل الخدمة (Service Worker)، فهو غير مرتبط بعلامة تبويب مفتوحة. يمكن للمستخدم بدء التنزيل، وإغلاق حاسوبه المحمول، والعودة إلى المنزل، وفتحه مرة أخرى، ليجد أن التنزيل قد اكتمل أو تقدم.
- كفاءة الموارد: المتصفح هو الأقدر على تحسين استخدام الموارد. يمكنه جدولة عمليات النقل للاستفادة من اتصالات الواي فاي، مما يوفر بيانات الهاتف المحمول، ويدير العمليات لتحسين عمر البطارية، وهو أمر بالغ الأهمية لمستخدمي الهواتف المحمولة في كل مكان.
- تجربة مستخدم متكاملة: يمكن للمتصفح توفير واجهة مستخدم أصلية على مستوى النظام للتنزيلات الجارية. يرى المستخدمون ويديرون تنزيلات الويب هذه في نفس المكان الذي يديرون فيه التنزيلات من التطبيقات الأصلية، مما يخلق تجربة سلسة ومألوفة. يشمل ذلك إشعارات بالتقدم والإكمال والفشل.
المكونات الأساسية: عمال الخدمة (Service Workers) و BackgroundFetchManager
لفهم الجلب في الخلفية، يجب أن تكون على دراية أولاً بمكونيه الأساسيين. إنهما يعملان جنبًا إلى جنب: أحدهما يبدأ الطلب من صفحة الويب، والآخر يدير النتيجة في الخلفية.
البطل المجهول: عامل الخدمة (Service Worker)
عامل الخدمة (Service Worker) هو نوع من عمال الويب (Web Worker)، وهو في الأساس نص جافاسكريبت يقوم متصفحك بتشغيله في الخلفية، بشكل منفصل تمامًا عن أي صفحة ويب. إنه يعمل كوكيل شبكة قابل للبرمجة، حيث يعترض ويتعامل مع طلبات الشبكة، ويدير ذاكرة التخزين المؤقت، ويمكّن الإشعارات الفورية. نظرًا لأنه يعمل بشكل مستقل، يمكنه أداء المهام حتى عندما لا يكون موقعك مفتوحًا في علامة تبويب بالمتصفح. بالنسبة للجلب في الخلفية، فإن عامل الخدمة هو البيئة المستمرة التي تستمع للنجاح النهائي أو فشل التنزيل، وتعالج الملفات الناتجة، وتحدث واجهة المستخدم أو تخزن الأصول مؤقتًا للاستخدام دون اتصال.
المنظم: BackgroundFetchManager
إن `BackgroundFetchManager` هو الواجهة، التي يمكن الوصول إليها من جافاسكريبت صفحة الويب الرئيسية، والتي تستخدمها لبدء وتكوين عملية جلب في الخلفية. يمكنك الوصول إليه من خلال كائن تسجيل عامل الخدمة: `navigator.serviceWorker.ready.then(swReg => swReg.backgroundFetch)`. طريقته الأساسية هي `fetch()`، والتي تأخذ معرفًا، وقائمة بالملفات المراد تنزيلها، ومجموعة من الخيارات. هذه الطريقة هي طلقة البداية؛ بمجرد استدعائها، يتولى المتصفح الأمر، وينتظر عامل الخدمة الخاص بك عند خط النهاية.
دليل تطبيقي خطوة بخطوة
لنسر في عملية تنفيذ تنزيل قابل للاستئناف لملف فيديو كبير. هذا المثال قابل للتطبيق عالميًا، سواء لمنصة وسائط في الولايات المتحدة، أو موقع تعليم إلكتروني في الهند، أو بوابة تدريب للشركات في ألمانيا.
الخطوة 1: التحقق من دعم المتصفح
قبل القيام بأي شيء آخر، يجب عليك التأكد من أن متصفح المستخدم يدعم واجهة برمجة تطبيقات الجلب في الخلفية. هذه الممارسة، المعروفة بالتحسين التدريجي، تضمن تجربة وظيفية للجميع، حتى لو لم يحصلوا على الميزات الأكثر تقدمًا.
في سكربت التطبيق الرئيسي الخاص بك، يمكنك التحقق من وجود `BackgroundFetchManager`:
if ('BackgroundFetchManager' in self) { // الواجهة مدعومة، يمكننا إظهار زر التنزيل المحسن } else { // الواجهة غير مدعومة، قدم حلاً بديلاً (مثل رابط عادي) }
الخطوة 2: تسجيل عامل خدمة
يعتمد الجلب في الخلفية بشكل أساسي على عامل الخدمة. إذا لم يكن لديك واحد بالفعل لتطبيق الويب التقدمي (PWA) الخاص بك، فستحتاج إلى إنشاء وتسجيل واحد. أنشئ ملفًا باسم `service-worker.js` في الدليل الجذر لمشروعك. ثم، قم بتسجيله من ملف جافاسكريبت الرئيسي الخاص بك:
async function registerServiceWorker() { if ('serviceWorker' in navigator) { try { const registration = await navigator.serviceWorker.register('/service-worker.js'); console.log('Service Worker registered successfully:', registration); } catch (error) { console.error('Service Worker registration failed:', error); } } } registerServiceWorker();
الخطوة 3: بدء عملية الجلب في الخلفية من الواجهة الأمامية
الآن، لنقم بإنشاء الدالة التي تبدأ التنزيل عندما ينقر المستخدم على زر. ستحصل هذه الدالة على تسجيل عامل الخدمة النشط ثم تستدعي `backgroundFetch.fetch()`.
const downloadVideoButton = document.getElementById('download-video-btn'); downloadVideoButton.addEventListener('click', async () => { try { // احصل على تسجيل عامل الخدمة const swReg = await navigator.serviceWorker.ready; // حدد تفاصيل التنزيل const videoUrl = '/assets/large-course-video.mp4'; const videoFileSize = 250 * 1024 * 1024; // 250 MB // ابدأ الجلب في الخلفية const bgFetch = await swReg.backgroundFetch.fetch('course-video-download-01', [videoUrl], { title: 'Module 1: Introduction to Web Development', icons: [{ sizes: '192x192', src: '/images/icons/icon-192.png', type: 'image/png', }], downloadTotal: videoFileSize, } ); console.log('Background Fetch started:', bgFetch); } catch (error) { console.error('Could not start Background Fetch:', error); } });
لنفصل معلمات `swReg.backgroundFetch.fetch()`:
- المعرف (`'course-video-download-01'`): معرف سلسلة نصية فريد لمهمة التنزيل المحددة هذه. ستستخدم هذا المعرف للإشارة إلى المهمة لاحقًا.
- الطلبات (`[videoUrl]`): مصفوفة من عناوين URL المراد جلبها. يمكنك تنزيل ملفات متعددة في مهمة واحدة مجمعة.
- الخيارات (`{...}`): كائن لتكوين التنزيل. تُستخدم `title` و `icons` من قبل المتصفح لإنشاء إشعار واجهة المستخدم الأصلي. `downloadTotal` هو الحجم الإجمالي المتوقع بالبايت لجميع الملفات مجتمعة؛ يعد توفير هذا أمرًا بالغ الأهمية للمتصفح لعرض شريط تقدم دقيق.
الخطوة 4: التعامل مع الأحداث في عامل الخدمة
بمجرد تسليم التنزيل إلى المتصفح، تكون مهمة كود الواجهة الأمامية قد انتهت في الوقت الحالي. يكمن باقي المنطق في `service-worker.js`، الذي سيتم إيقاظه بواسطة المتصفح عند اكتمال المهمة أو فشلها.
تحتاج إلى الاستماع لحدثين رئيسيين: `backgroundfetchsuccess` و `backgroundfetchfail`.
// في ملف service-worker.js self.addEventListener('backgroundfetchsuccess', (event) => { const bgFetch = event.registration; event.waitUntil(async function () { console.log(`Background fetch '${bgFetch.id}' completed successfully.`); // افتح ذاكرة التخزين المؤقت حيث سنخزن ملفاتنا التي تم تنزيلها const cache = await caches.open('downloaded-assets-v1'); // احصل على جميع سجلات الملفات التي تم تنزيلها const records = await bgFetch.matchAll(); // لكل سجل، قم بتخزين الاستجابة في ذاكرة التخزين المؤقت const promises = records.map(async (record) => { const response = record.response.clone(); await cache.put(record.request, response); }); await Promise.all(promises); // اختياري: تحديث عنوان واجهة المستخدم في إشعار التنزيل await event.updateUI({ title: 'Download complete and ready!' }); }()); }); self.addEventListener('backgroundfetchfail', (event) => { const bgFetch = event.registration; console.error(`Background fetch '${bgFetch.id}' failed.`); // اختياري: تحديث واجهة المستخدم لتعكس الفشل event.updateUI({ title: 'Download failed. Please try again.' }); });
في معالج النجاح، نفتح تخزين ذاكرة التخزين المؤقت (Cache Storage)، ونسترجع جميع الملفات التي تم تنزيلها باستخدام `bgFetch.matchAll()`، ثم نضع كل واحد منها في ذاكرة التخزين المؤقت. هذا يجعل الفيديو متاحًا للتشغيل دون اتصال بواسطة تطبيق الويب الخاص بك.
الخطوة 5: مراقبة التقدم وتفاعل المستخدم
تتضمن تجربة المستخدم الرائعة تقديم ملاحظات. عندما ينقر المستخدم على إشعار التنزيل الذي يوفره المتصفح، يجب أن نأخذه إلى صفحة ذات صلة في تطبيقنا. نتعامل مع هذا الأمر باستخدام حدث `backgroundfetchclick` في عامل الخدمة.
// في ملف service-worker.js self.addEventListener('backgroundfetchclick', (event) => { const bgFetch = event.registration; if (bgFetch.id === 'course-video-download-01') { event.waitUntil( clients.openWindow('/downloads') ); } });
يخبر هذا الكود المتصفح بفتح صفحة `/downloads` في موقعك على الويب عندما ينقر المستخدم على الإشعار الخاص بمهمة التنزيل المحددة هذه. في تلك الصفحة، يمكنك بعد ذلك عرض تقدم التنزيل أو قائمة بالتنزيلات المكتملة.
سحر الاستئناف: كيف يعمل بالفعل؟
إن الجانب الأقوى وربما الأكثر سوء فهم في الجلب في الخلفية هو قدرته على الاستئناف التلقائي. كيف يعمل دون الحاجة إلى كتابة أي كود خاص لذلك؟
الجواب هو أنك قمت بتفويض المسؤولية إلى عملية على مستوى النظام ومحسّنة للغاية: مدير التنزيل الخاص بالمتصفح نفسه. عندما تبدأ عملية جلب في الخلفية، فإنك لا تدير البايتات عبر الشبكة مباشرةً. بل المتصفح هو من يفعل ذلك.
إليك تسلسل الأحداث أثناء انقطاع الشبكة:
- يقوم المستخدم بتنزيل ملف، ويفقد جهازه الاتصال بالشبكة (على سبيل المثال، يدخل نفقًا).
- يكتشف مدير التنزيل في المتصفح فشل الشبكة ويوقف النقل برشاقة. يحتفظ بتتبع عدد البايتات التي تم استلامها بنجاح.
- يستعيد جهاز المستخدم الاتصال بالشبكة لاحقًا.
- يحاول المتصفح تلقائيًا استئناف التنزيل. يرسل طلب HTTP جديدًا إلى الخادم لنفس الملف، ولكن هذه المرة يتضمن رأس `Range`، ليخبر الخادم فعليًا، "لدي بالفعل أول 'X' بايت، من فضلك أرسل لي الباقي، بدءًا من البايت 'X+1'."
- سيستجيب الخادم المكوّن بشكل صحيح بحالة `206 Partial Content` ويبدأ في بث بقية الملف.
- يضيف المتصفح هذه البيانات الجديدة إلى الملف الذي تم تنزيله جزئيًا.
هذه العملية بأكملها شفافة بالنسبة لكود جافاسكريبت الخاص بك. يتم إخطار عامل الخدمة الخاص بك فقط في النهاية، عندما يتم تنزيل الملف بالكامل وتجميعه بنجاح، أو إذا فشلت العملية بشكل نهائي (على سبيل المثال، لم يعد الملف موجودًا على الخادم). هذا التجريد قوي بشكل لا يصدق، حيث يحرر المطورين من بناء منطق استئناف تنزيل معقد وهش.
مفاهيم متقدمة وأفضل الممارسات لجمهور عالمي
توفير `downloadTotal` دقيق
خيار `downloadTotal` هو أكثر من مجرد ميزة لطيفة. بدونه، لا يمكن للمتصفح عرض سوى مؤشر تقدم غير محدد (مثل أيقونة تدور). باستخدامه، يمكنه عرض شريط تقدم دقيق وحساب الوقت المتبقي المقدر. هذا يحسن تجربة المستخدم بشكل كبير. للحصول على هذه القيمة، قد تحتاج إلى إجراء طلب `HEAD` إلى عنوان URL للملف مسبقًا للتحقق من رأس `Content-Length`، أو يمكن لواجهة برمجة التطبيقات الخاصة بك توفير أحجام الملفات كجزء من بياناتها الوصفية.
إدارة ملفات متعددة في عملية جلب واحدة
تتألق واجهة برمجة التطبيقات عند تجميع الأصول ذات الصلة. تخيل مستخدمًا يقوم بتنزيل معرض صور، أو حزمة برامج مع وثائقها، أو مستوى لعبة فيديو بجميع موادها وملفاتها الصوتية. يمكنك تمرير مصفوفة من عناوين URL إلى `backgroundFetch.fetch()`. يتم التعامل مع هذا كمهمة ذرية واحدة من قبل المتصفح، مع إشعار واحد وشريط تقدم واحد للحزمة بأكملها. في معالج `backgroundfetchsuccess` الخاص بك، سيعيد `bgFetch.matchAll()` مصفوفة من السجلات، والتي يمكنك بعد ذلك معالجتها بشكل فردي.
التعامل مع الأخطاء وسيناريوهات الفشل
يمكن أن يفشل التنزيل لأسباب عديدة: يعيد الخادم خطأ 404، أو تنفد مساحة القرص لدى المستخدم، أو يقوم المستخدم بإلغاء التنزيل يدويًا من واجهة مستخدم المتصفح. معالج حدث `backgroundfetchfail` الخاص بك هو شبكة الأمان. يمكنك استخدامه لتنظيف أي بيانات جزئية، وإخطار المستخدم داخل تطبيقك، وربما عرض زر إعادة المحاولة. إن فهم أن الفشل احتمال وارد هو مفتاح بناء نظام قوي.
تخزين الأصول التي تم تنزيلها باستخدام Cache API
المكان الأكثر شيوعًا وفعالية لتخزين أصول الويب التي تم تنزيلها هو واجهة برمجة تطبيقات ذاكرة التخزين المؤقت (Cache API). إنها آلية تخزين مصممة خصيصًا لكائنات `Request` و `Response`. عن طريق وضع ملفاتك التي تم تنزيلها في ذاكرة التخزين المؤقت، يمكنك لاحقًا خدمتها مباشرة من عامل الخدمة عندما يحاول المستخدم الوصول إليها، مما يجعل تطبيقك قادرًا على العمل دون اتصال بالإنترنت حقًا.
حالات الاستخدام عبر مختلف الصناعات
تطبيقات الجلب في الخلفية واسعة وتشمل العديد من الصناعات العالمية:
- الإعلام والترفيه: يمكن لخدمات البث المستندة إلى الويب تقديم وضع عدم الاتصال، مما يسمح للمستخدمين في أي بلد بتنزيل الأفلام أو الموسيقى للرحلات الجوية أو التنقلات، تمامًا مثل نظيراتها من التطبيقات الأصلية.
- التعليم والتعلم الإلكتروني: يمكن لجامعة في إفريقيا توفير بوابة ويب للطلاب لتنزيل محاضرات الفيديو الكبيرة ومواد الدورة التفاعلية، مما يضمن أن حتى أولئك الذين لديهم إنترنت منزلي ضعيف يمكنهم الوصول إلى تعليمهم.
- الشركات والخدمات الميدانية: يمكن لشركة تصنيع عالمية تزويد مهندسيها الميدانيين بتطبيق ويب تقدمي يسمح لهم بتنزيل المخططات ثلاثية الأبعاد الضخمة والكتيبات الفنية للآلات قبل التوجه إلى موقع بعيد لا يوجد به اتصال بالإنترنت.
- السفر والسياحة: يمكن لتطبيق سفر أن يسمح للمستخدمين بتنزيل خرائط غير متصلة بالإنترنت وأدلة مدن ومعلومات التذاكر لوجهتهم، مما يوفر عليهم رسوم التجوال الدولي الباهظة للبيانات.
توافق المتصفحات والنظرة المستقبلية
حتى وقت كتابة هذا التقرير، فإن واجهة برمجة تطبيقات الجلب في الخلفية مدعومة بشكل أساسي في المتصفحات المستندة إلى Chromium مثل Google Chrome و Microsoft Edge. من المهم التحقق من مصادر مثل CanIUse.com أو MDN Web Docs للحصول على أحدث معلومات التوافق. على الرغم من أنها لم تُعتمد عالميًا بعد، إلا أن وجودها في المتصفحات الرئيسية يمثل خطوة مهمة إلى الأمام. مع استمرار تطور منصة الويب، تعمل واجهات برمجة التطبيقات مثل هذه على سد فجوة القدرات بين تطبيقات الويب والتطبيقات الأصلية، مما يمهد الطريق لجيل جديد من تطبيقات الويب التقدمية القوية والمرنة والمتاحة عالميًا.
الخلاصة: بناء ويب أكثر مرونة للجميع
إن واجهة برمجة تطبيقات الجلب في الخلفية هي أكثر من مجرد أداة لتنزيل الملفات. إنها تعبير عن نوع الويب الذي نريد بناءه: ويب مرن، يتمحور حول المستخدم، ويعمل للجميع، بغض النظر عن أجهزتهم أو جودة اتصالهم بالشبكة. من خلال تفويض عمليات النقل الكبيرة إلى المتصفح، نحرر مستخدمينا من قلق مشاهدة شريط التقدم، ونوفر بياناتهم وبطارياتهم، ونقدم تجربة قوية وموثوقة.
بينما تخطط لمشروع الويب التالي الذي يتضمن عمليات نقل ملفات كبيرة، انظر إلى ما هو أبعد من `fetch` التقليدي. ضع في اعتبارك السياق العالمي لمستخدميك واعتمد قوة الجلب في الخلفية لبناء تطبيق حديث حقًا يعتمد على العمل دون اتصال بالإنترنت. مستقبل الويب مستمر ومرن، والآن، يمكن أن تكون تنزيلاتك كذلك أيضًا.